<template>
  <div class="doodlemin-view" :style="{width: 'auto'}">
    <div class="doodlemin-view-content" v-loading='loading' :style="{height: height+'px'}">
      <canvas class="doodlemin-canvas" :class="isClear && 'clear'" ref="doodleminCanvas" :width="loading ? 0 : imgWidth" :height="loading ? 0 : imgHeight" :style="{opacity: markOpacity}" />
      <img class="doodlemin-img" :src="src" :width="loading ? 0 : imgWidth" :height="loading ? 0 : imgHeight" @load="resetZoom" />
    </div>

    <!-- 操作选项 -->
    <div class="doodlemin-handle-option">
      <div class="option-line-width">
        <div class="line-width-cont">
          <div class="line-width" v-for="(v,i) in lineWidth||[]" :key="'lw-'+i" :class="currentLineWidth == v && 'current'" :data-width="v" @click="selectLineWidth">
            <div class="line-color" :style="{width: v+'px', height:v+'px',background: strokeStyle, opacity: markOpacity}"></div>
          </div>
        </div>
      </div>
    </div>

    <!-- 操作按钮群 -->
    <div class="doodlemin-handle">
      <div>
        <div class="doodlemin-btn" :class="!isClear && 'current'" @click="isClear=false">涂抹</div>
        <div class="doodlemin-btn" :class="isClear && 'current'" @click="isClear=true">擦除</div>
        <div class="doodlemin-btn" :class="(historyIndex == -1) && 'disable'" @click="back">撤销</div>
        <div class="doodlemin-btn" :class="(historyIndex >= history.length-1) && 'disable'" @click="redo">重做</div>
      </div>
      <div>
        <div class="doodlemin-btn" @click="outputMark">确定</div>
      </div>
    </div>

  </div>
</template>

<script>
/* eslint-disable */
export default {
  name: 'Doodle',
  props: {
    // 图片url
    src: {
      type: String,
      default: ''
    },
    // 宽度
    width: {
      type: Number,
      default: 500
    },
    // 高度
    height: {
      type: Number,
      default: 300
    },
    // 画笔颜色
    strokeStyle: {
      type: String,
      default: '#40387C'
    },
    // 画笔粗细
    lineWidth: {
      type: Array,
      default: [6, 10, 14, 18, 22]
    },
    // 遮罩透明度
    markOpacity: {
      type: Number,
      default: 0.6
    },
  },
  data () {
    return {
      history: [],          // 历史记录
      historyIndex: -1,     // 历史记录下标
      dragging: false,      // 是否绘制中
      isClear: false,       // 是否为擦除模式
      imgWidth: 500,        // 图像原始宽度，同时作用于画布
      imgHeight: 300,       // 图像原始高度，同时作用于画布
      zoom: 1,              // 缩放比例
      markImageOriginal: null,      // 原始遮罩图：base64
      markImage: null,      // 遮罩图：base64
      currentLineWidth: 10, // 当前笔触大小
      loading: true,        // 图片是否加载中

      canvas: null,
      ctx: null,
      canvasPos: null,
      shadowCanvas: null,
      shadowCtx: null,
      shadowHistory: [],
    }
  },
  created() {
    setTimeout(() => {
      this.init()
    }, 500)
  },
  watch: {
    src: {
      handler() {
        this.resetAll()
      },
      immediate: true
    },
  },
  methods: {
    /** 初始化 */
    init() {
      this.canvas = this.$refs['doodleminCanvas']
      this.ctx = this.canvas.getContext('2d',{willReadFrequently:true})
      this.canvasPos = this.canvas.getBoundingClientRect()
			this.canvas.onmousedown = e => this.onMousedown(e)
      this.canvas.onmousemove = e => this.onMousemove(e)
      this.canvas.onmouseup = e => this.onMouseup(e)
      this.canvas.onmouseout = e => this.onMouseout(e)

      this.currentLineWidth = this.lineWidth[0]
    },
    /** 重置比例 */
    resetZoom(e) {
      this.loading = true
      let img = new Image()
      img.src = this.src
      img.onload = (e2) => {
        let w = e2.currentTarget.width
        let h = e2.currentTarget.height
        // 计算缩放比例(原图/指定尺寸)
        this.shadowCanvas = document.createElement('canvas')
        this.shadowCtx = this.shadowCanvas.getContext('2d',{willReadFrequently:true})
        this.shadowCanvas.width = w
        this.shadowCanvas.height = h
        // 计算纵横比
        let width = this.width
        let height = parseInt(h * (this.width / w))
        if (w >= h) {
          if (height > this.height) {
            width = parseInt(w * (this.height / h))
            height = this.height
          }
          this.zoom = w / width
        } else {
          width = parseInt(w * (this.height / h))
          height = this.height
          if (width > this.width) {
            width = this.width
            height = parseInt(h * (this.width / w))
          }
          this.zoom = h / height
        }
        this.imgWidth = width
        this.imgHeight = height
        this.loading = false
      }
    },
    /** 重置所有设置 */
    resetAll() {
      if (this.ctx) {
        this.isClear = false
        this.historyIndex = -1
        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
        this.history = []
        this.shadowCtx.clearRect(0, 0, this.shadowCanvas.width, this.shadowCanvas.height)
        this.shadowHistory = []
        // 重新读取图片和比例
        this.resetZoom()
      }
    },
    /** 变更图片 */
    onChangeImage() {
      this.resetAll()
    },
    /** 鼠标按下 */
    onMousedown(e) {
      this.dragging = true
      if (!this.isClear) {
        let pos = this.getCursorPosition(e)
        this.ctx.strokeStyle = this.strokeStyle
        this.ctx.lineWidth = this.currentLineWidth
        this.ctx.lineCap = 'round'
        this.ctx.lineJoin = 'round'
        this.ctx.beginPath()
        this.ctx.moveTo(pos.x, pos.y)

        this.shadowCtx.strokeStyle = this.strokeStyle
        this.shadowCtx.lineWidth = this.currentLineWidth*this.zoom
        this.shadowCtx.lineCap = 'round'
        this.shadowCtx.lineJoin = 'round'
        this.shadowCtx.beginPath()
        this.shadowCtx.moveTo(pos.x*this.zoom, pos.y*this.zoom)
      } else {
        this.clear(e)
      }
    },
    /** 鼠标移动 */
    onMousemove(e) {
      if (!this.dragging) {
        return
      }
      if (!this.isClear) {
        let pos = this.getCursorPosition(e)
        this.ctx.lineTo(pos.x, pos.y)
        this.ctx.stroke()

        this.shadowCtx.lineTo(pos.x*this.zoom, pos.y*this.zoom)
        this.shadowCtx.stroke()
      } else {
        this.clear(e)
      }
    },
    /** 放开鼠标 */
    onMouseup(e) {
      this.dragging = false
      this.save()
    },
    /** 移出画布 */
    onMouseout(e) {
      this.dragging = false
    },
    getCursorPosition(e) {
      return { x: e.offsetX, y: e.offsetY }
      // return {
      //   x: e.clientX - this.canvasPos.left,
      //   y: e.clientY - this.canvasPos.top
      // }
    },
    /** 擦除 */
    clear(e) {
      let pos = this.getCursorPosition(e)
      let lineWidth = this.currentLineWidth
      this.ctx.save()
      this.ctx.beginPath()
      this.ctx.arc(pos.x, pos.y, lineWidth/2, 0, Math.PI * 2)
      this.ctx.clip()
      this.ctx.clearRect(pos.x - lineWidth/2, pos.y - lineWidth/2, lineWidth, lineWidth)
      this.ctx.restore()

      this.shadowCtx.save()
      this.shadowCtx.beginPath()
      this.shadowCtx.arc(pos.x*this.zoom, pos.y*this.zoom, (lineWidth*this.zoom)/2, 0, Math.PI * 2)
      this.shadowCtx.clip()
      this.shadowCtx.clearRect(pos.x*this.zoom - (lineWidth*this.zoom)/2, pos.y*this.zoom - (lineWidth*this.zoom)/2, lineWidth*this.zoom, lineWidth*this.zoom)
      this.shadowCtx.restore()
    },

    /** 写入历史记录 */
    save() {
      this.history.length = this.historyIndex + 1
      let data = this.ctx.getImageData(0, 0, this.canvas.width, this.canvas.height)
      this.history.push(data)

      this.shadowHistory.length = this.historyIndex + 1
      let data2 = this.shadowCtx.getImageData(0, 0, this.shadowCanvas.width, this.shadowCanvas.height)
      this.shadowHistory.push(data2)

      this.historyIndex += 1
    },
    /** 后退历史记录 */
    back() {
      this.historyIndex -= 1
      if (this.historyIndex < 0) {
        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
        this.shadowCtx.clearRect(0, 0, this.shadowCanvas.width, this.shadowCanvas.height)
        this.historyIndex = -1
        return
      }
      let data = this.history[this.historyIndex]
      if (!data) return

      this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
      this.ctx.putImageData(data, 0, 0)

      let data2 = this.shadowHistory[this.historyIndex]
      this.shadowCtx.clearRect(0, 0, this.shadowCanvas.width, this.shadowCanvas.height)
      this.shadowCtx.putImageData(data2, 0, 0)
    },
    /** 重做历史记录 */
    redo() {
      this.historyIndex += 1
      if (this.historyIndex >= this.history.length) {
        this.historyIndex = this.history.length - 1
        return
      }
      let data = this.history[this.historyIndex]
      if (!data) return

      this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
      this.ctx.putImageData(data, 0, 0)

      let data2 = this.shadowHistory[this.historyIndex]
      this.shadowCtx.clearRect(0, 0, this.shadowCanvas.width, this.shadowCanvas.height)
      this.shadowCtx.putImageData(data2, 0, 0)
    },
    /** 输出遮罩 */
    outputMark() {
      let w = this.shadowCanvas.width
      let h = this.shadowCanvas.height
      let imgData = this.shadowCtx.getImageData(0, 0, w, h)
      let data = imgData.data
      for (let i2 = 0; i2 < data.length; i2 += 4) {
        if (data[i2 + 3] > 0) {
          data[i2 + 0] = data[i2 + 1] = data[i2 + 2] = 255
        }
      }
      let canvas = document.createElement('canvas'),
          canvas2 = document.createElement('canvas'),
          img = new Image()
      canvas2.width = canvas.width = w
      canvas2.height = canvas.height = h
      let ctx = canvas.getContext('2d',{willReadFrequently:true}),
          ctx2 = canvas2.getContext('2d',{willReadFrequently:true})
      ctx.putImageData(imgData, 0, 0)
      img.src = canvas.toDataURL()
      img.onload = () => {
        ctx2.fillStyle = '#000000'
        ctx2.fillRect(0, 0, w, h)
        ctx2.drawImage(img, 0, 0)
        this.markImageOriginal = this.shadowCanvas.toDataURL()
        this.markImage = canvas2.toDataURL()
        canvas.remove()
        canvas2.remove()
        img.remove()
        this.$emit('comfirm', {original: this.markImageOriginal, mark: this.markImage})
      }
    },

    /** 选择笔触 */
    selectLineWidth(e) {
      let width = e.currentTarget.dataset.width
      this.currentLineWidth = width
    }
  }
}
</script>
<style lang="scss" scoped>
.doodlemin-view {
}
.doodlemin-view-content {
  position: relative;
  background: #eeeeee;
}

.doodlemin-handle {
  box-sizing: border-box;
  display: flex;
  justify-content: space-between;
  padding: 4px;
}

.doodlemin-handle-option {
  box-sizing: border-box;
  padding: 10px;
  text-align: center;
}
.option-line-width {
  box-sizing: border-box;
  display: inline-block;
  background: #eeeeee;
  border-radius: 999px;
}
.line-width-cont {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.doodlemin-handle-option {
  .line-width {
    border: 2px solid #eeeeee;
    border-radius: 999px;
    cursor: pointer;
    margin: 4px 8px;
  }
  .line-width.current {
    border-color: #fc941d;
  }
  .line-color {
    border-radius: 999px;
  }
}

.doodlemin-canvas,
.doodlemin-img {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  user-select: none;
}
.doodlemin-canvas {
  cursor: pointer;
  z-index: 2;
}
.doodlemin-canvas.clear {
  /* cursor: url('/src/assets/icon/eraser.cur') 16 16, auto; */
}
.doodlemin-btn {
  user-select: none;
  display: inline-block;
  border: 1px solid #cccccc;
  border-radius: 999px;
  padding: 4px 8px;
  margin: 0 4px;
  &.current {
    background: #fc941d;
    border: 1px solid #fc941d;
    color: #ffffff;
  }
  &.disable {
    opacity: 0.4;
  }
}
</style>